const { tokenSetting } = require('../setting')
const { login } = require('../controllers/userController')
const enums = require('../enums')
const {
  genToken,
  removeToken,
  validToken,
  getTokenDataByUserKey,
} = require('../utils/token')
const response = require('../utils/response')

// 条件判断太多层了，需要优化
module.exports = async function authMiddleware(ctx, next) {
  const url = ctx.url
  if (tokenSetting.AuthExcludePaths.includes(url)) {
    // 不需要验证的路径
    await next()
    return
  }
  if (url === tokenSetting.LoginPath) {
    // 登录流程
    const userData = await login(ctx)
    if (userData.code === enums.SUCCESS) {
      // 登录校验通过，生成token
      let resp
      if (tokenSetting.MultiLogin) {
        // 支持多端重复登录，返回相同token
        const userCache = await getTokenDataByUserKey(userData.userKey)
        if (userCache) {
          resp = genToken(userData.userKey, userData.data, userCache.uuid)
        } else {
          resp = genToken(userData.userKey, userData.data)
        }
      } else {
        resp = genToken(userData.userKey, userData.data)
      }
      if (resp.isSuccess()) {
        response.SuccssWithData(ctx, resp.data)
        return
      }
      response.FailWithCode(ctx, resp.code, resp.msg)
      return
    }
    if (userData.code === enums.USER_INFO_ERROR) {
      response.FailWithCode(ctx, userData.code, '用户名或密码不正确')
      return
    }
    if (userData.code === enums.USER_NOT_FOUND) {
      response.FailWithCode(ctx, userData.code, '用户不存在或被注销')
      return
    }
  }
  // 检查是否携带正确格式的token
  if (!ctx.request.header.authorization) {
    response.FailWithCode(ctx, enums.AUTH_TIMEOUT, '请携带token访问')
    return
  }
  const tokenArr = ctx.request.header.authorization.split(' ')
  if (tokenArr.length < 2 || tokenArr[0] != 'Bearer') {
    response.FailWithCode(ctx, enums.FAIL, 'token格式不正确')
    return
  }
  // 校验token
  const tokenData = await validToken(tokenArr[1])
  if (!tokenData.isSuccess()) {
    response.FailWithCode(ctx, tokenData.code, tokenData.msg)
    return
  }
  ctx.user = tokenData.data
  if (url === tokenSetting.LogoutPath) {
    // 登出流程
    const resp = removeToken(tokenArr[1])
    if (resp.isSuccess()) {
      response.Success(ctx)
      return
    }
    response.FailWithCode(ctx, resp.code, resp.msg)
    return
  }
  // 继续执行下去
  await next()
}
